package com.quyunshuo.module.home.view

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.util.Log
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.widget.Scroller
import androidx.core.view.GestureDetectorCompat
import com.quyunshuo.module.home.R
import kotlin.math.abs
import kotlin.math.roundToInt

/**
 * 时间滑动控件
 *
 * 功能：实现循环滚动的数字选择器
 * 设计：
 *     1. 继承自 View 实现自定义绘制
 *     2. 使用 Scroller 实现平滑滚动效果
 *     3. 使用 GestureDetector 处理复杂手势（拖动、快速滑动等）
 *     4. 使用 Paint 进行文本绘制
 */
class CircularPickerView @JvmOverloads constructor(
    context: Context,  // 上下文对象
    attrs: AttributeSet? = null,  // XML属性集
    defStyleAttr: Int = 0  // 默认样式属性
) : View(context, attrs, defStyleAttr) {  // 继承View类实现自定义控件

    // 自定义属性（从XML读取）
    private var minValue = 0  // 可选最小值（如0小时）
    private var maxValue = 23 // 可选最大值（如23小时）
    private var textSize = 48f  // 文本字体大小（单位：像素）
    private var selectedColor = 0xFF3F51B5  // 选中项的颜色值
    private var normalColor = 0xFF9E9E9E    // 普通项的颜色值

    // 绘制相关属性
    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {  // 创建带抗锯齿的画笔
        textAlign = Paint.Align.CENTER  // 文字居中绘制
    }
    private val rect = Rect()  // 用于测量文本边界
    private var itemHeight = 0  // 每个选项的高度

    // 滚动控制参数
    private var selectedValue = 0  // 当前选中值（如12）
    private var scrollOffset = 0   // 滚动偏移量（核心滚动状态）
    private var lastPosition = 0   // 最后位置记录（用于回弹计算）

    // 手势与动画工具
    private val scroller = Scroller(context)  // 滚动控制器（实现平滑滚动）
    private val gestureDetector = GestureDetectorCompat(context, GestureListener())  // 手势识别器

    // 初始化块（View构造时执行）
    init {
        // 获取XML中的自定义属性
        context.obtainStyledAttributes(attrs, R.styleable.CircularPickerView).apply {
            // 读取各属性值（使用默认值作为后备）
            minValue = getInt(R.styleable.CircularPickerView_minValue, 0)
            maxValue = getInt(R.styleable.CircularPickerView_maxValue, 23)
            textSize = getDimension(R.styleable.CircularPickerView_textSize, 48f)
            selectedColor = getColor(R.styleable.CircularPickerView_selectedColor, 0xFF3F51B5.toInt()).toLong()
            normalColor = getColor(R.styleable.CircularPickerView_normalColor, 0xFF9E9E9E.toInt()).toLong()
            recycle()  // 回收TypedArray（必须调用）
        }

        // 初始化选中值为最小值
        selectedValue = minValue

        // 设置触摸事件监听器
        setOnTouchListener { _, event ->
            // 优先交给手势识别器处理，若未处理则使用自定义触摸逻辑
            gestureDetector.onTouchEvent(event) || handleTouch(event)
        }
    }

    // 设置可选值范围（如0-59分钟）
    fun setValueRange(min: Int, max: Int) {
        require(min < max) { "Min value must be less than max value" }  // 参数检查
        minValue = min
        maxValue = max
        // 确保选中值在新范围内
        selectedValue = minValue.coerceAtLeast(selectedValue).coerceAtMost(maxValue)
        invalidate()  // 触发重绘
    }

    // 获取当前选择的值
    fun getSelectedValue(): Int = selectedValue

    // 设置当前选中的值
    fun setSelectedValue(value: Int) {
        // 确保值在有效范围内
        selectedValue = value.coerceIn(minValue, maxValue)
        invalidate()  // 触发重绘
    }

    // View尺寸测量方法
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

        // 计算单个选项的高度（基于文本尺寸）
        paint.textSize = textSize
        // 测量"0"字符的边界
        paint.getTextBounds("0", 0, 1, rect)
        // 行高 = 文本高度 × 2（留出间距）
        itemHeight = rect.height() * 2

        // 设置最终测量尺寸
        setMeasuredDimension(
            resolveSize(suggestedMinimumWidth, widthMeasureSpec),  // 宽度
            resolveSize(itemHeight * 5, heightMeasureSpec)  // 高度（显示5行）
        )
    }

    // View绘制方法
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        // 计算控件中心点坐标
        val centerY = height / 2f
        val centerX = width / 2f

        // 绘制可见项目（中心项+上下各一项）
        for (i in -1..1) {
            // 计算实际位置（基于当前滚动偏移）
            val position = scrollOffset + i
            // 将位置映射为具体值（实现循环效果）
            val value = mapPositionToValue(position)
            // 计算该位置的Y坐标
            val y = centerY + (position - scrollOffset) * itemHeight

            // 计算透明度（离中心越远越透明）
            var alpha = 255 - (abs(y - centerY) / centerY * 200).toInt().coerceIn(0, 255)

            // 配置画笔属性
            paint.apply {
                // 中心项使用选中色，其他用普通色
                color = if (abs(y - centerY) < 1) selectedColor.toInt() else normalColor.toInt()
                // 中心项完全不透明
                alpha = if (abs(y - centerY) < 1) 255 else alpha
                // 中心项放大1.2倍（视觉强调）
                textSize = if (abs(y - centerY) < 1) this@CircularPickerView.textSize * 1.2f
                else this@CircularPickerView.textSize
            }

            // 绘制文本
            canvas.drawText(formatValue(value), centerX, y, paint)
        }
    }

    // 触摸事件处理（覆盖View的方法）
    override fun onTouchEvent(event: MotionEvent): Boolean {
        // 委托给自定义触摸处理器
        return handleTouch(event)
    }

    // 自定义触摸处理逻辑
    private fun handleTouch(event: MotionEvent): Boolean {
        // 根据触摸事件类型处理
        when (event.actionMasked) {
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                // 记录最后位置
                lastPosition = scrollOffset
                // 执行回弹对齐
                alignPicker()
                return true
            }
        }
        return false
    }

    // Scroller回调（实现平滑滚动）
    override fun computeScroll() {
        // 检查滚动状态
        if (scroller.computeScrollOffset()) {
            // 计算新的滚动偏移（基于Item高度）
            scrollOffset = (scroller.currY / itemHeight.toFloat()).roundToInt()
            // 更新选中值
            selectedValue = mapPositionToValue(scrollOffset)
            // 触发回调
            itemClickCallback?.invoke(selectedValue)
            // 重绘界面
            invalidate()
        }
    }

    // 核心方法：将滚动位置映射为循环值（如0-23小时循环）
    private fun mapPositionToValue(position: Int): Int {
        // 计算有效项总数
        val totalItems = maxValue - minValue + 1
        // 映射算法：
        return minValue + ((position - minValue) % totalItems).let {
            // 处理负值（实现循环效果）
            if (it < 0) it + totalItems else it
        }
    }

    // 格式化显示值（对分钟自动补0）
    private fun formatValue(value: Int): String {
        // 0-59分钟时显示两位数（如"05"）
        return if (minValue == 0 && maxValue == 59)
            String.format("%02d", value)
        else
            value.toString()
    }

    // 惯性滚动结束后对齐到最近的整数位置
    private fun alignPicker() {
        // 计算目标位置（用于回弹）
        val targetPosition = lastPosition + scrollOffset
        // 启动滚动动画
        scroller.startScroll(
            0, (scrollOffset * itemHeight),  // 起始位置
            0, ((targetPosition - scrollOffset) * itemHeight),  // 滚动距离
            300  // 动画时长（毫秒）
        )
        // 重绘界面
        invalidate()
    }

    // 选中值变化回调
    private var itemClickCallback: ((Int) -> Unit)? = null

    // 设置回调监听器
    fun setCallback(callback: (Int) -> Unit) {
        itemClickCallback = callback
    }

    // 内部手势监听器实现
    private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
        // 手指按下事件
        override fun onDown(e: MotionEvent): Boolean {
            // 强制停止当前滚动动画（响应新触摸）
            scroller.forceFinished(true)
            return true  // 表明消费事件
        }

        // 拖动事件处理（主要滚动逻辑）
        override fun onScroll(
            e1: MotionEvent?,  // 起始事件
            e2: MotionEvent,   // 当前事件
            distanceX: Float,  // X方向移动距离
            distanceY: Float   // Y方向移动距离
        ): Boolean {
            // 根据移动距离计算新的滚动偏移
            // 注意：乘以2是为了提高滚动灵敏度
            scrollOffset += (distanceY / itemHeight * 2).toInt()
            // 记录当前位置（用于回弹）
            lastPosition = scrollOffset
            // 更新选中值
            selectedValue = mapPositionToValue(scrollOffset)
            // 重绘界面
            invalidate()
            return true
        }

        // 快速滑动（fling）事件处理
        override fun onFling(
            e1: MotionEvent?,   // 起始事件
            e2: MotionEvent,    // 结束事件
            velocityX: Float,   // X方向速度（像素/秒）
            velocityY: Float    // Y方向速度（像素/秒）
        ): Boolean {
            // 使用Scroller实现惯性滚动
            scroller.fling(
                0, scrollOffset * itemHeight,  // 起始位置
                0, -velocityY.toInt(),         // 速度（取负因坐标系方向）
                0, 0,  // X边界（无限制）
                Int.MIN_VALUE, Int.MAX_VALUE   // Y边界（无限制）
            )
            return true
        }
    }
}